<?php
//require 访问控制类
require_once 'AccessControl.php';
require_once 'Validator.php';

class AnswerController extends Zend_Controller_Action
{

    protected $ecodes = null;
    protected $ecodesId = null;
    protected $langType = null;
    
    public function init()
    {
        $this->access = new AccessControl(); //实例化访问控制类
        $this->Validator = new Validator(); //实例化验证类
        $this->ecodes = array(
            '$10000001'=>'编译通过!',
            '$10000009'=>'运行超时..',
            '$1000000A'=>'输出错误..',
            '$1000000B'=>'内存超限..'
            );
        
        $this->ecodesId = array(
            '$10000001'=>'success',
            '$10000009'=>'exception',
            '$1000000A'=>'wrong',
            '$1000000B'=>'exception'
        );
        //文件类型数组
        $this->langType = array('1'=>'.c','2'=>'.cpp','3'=>'.java','4'=>'pas','5'=>'.py');
    }

    public function indexAction()
    {
        // action body
    }

    //提交问题答案
    public function submitAction()
    {
        //是否登录
        if(!$this->access->isLogin())
        {
            $this->_redirect('/User/login');
        }
        
        $request=$this->getRequest();
        $qid = $request->getUserParam('qid'); //题目ID
        $aid = $request->getuserParam('aid'); //答案ID
        
        $user = $this->access->getSession();
        
        $submitForm = new Zend_Form();
        $submitForm->setMethod('post');
        
        $submitQid = new Zend_Form_Element_Text('qid');
        $submitQid->setLabel('题目编号')
                ->setRequired(true)
                ->addFilter('StringTrim')
                ->setAttrib('MaxLength', '4')
                ->setAttrib('size','7')
                ->setAttrib('onkeyup',"value=this.value.replace(/\D+/g,'')")
                ->setAttrib('class','border')
                ->addValidator('Digits')
                ->addValidator('NotEmpty');

        $submitLang = new Zend_Form_Element_Select('language');
        $submitLang->setLabel('选择语言')
                ->setRequired(true)
                ->setAttrib('onchange','selectLanguage(this)')
                ->setAttrib('class','border')
                ->addMultiOption('1','C')
                ->addMultiOption('2','C++')
                ->addMultiOption('3','Java')
                ->addMultiOption('4','Pascal')
                ->addMultiOption('5','Python');
        
        $submitTextarea = new Zend_Form_Element_Textarea('code');
        $submitTextarea->setLabel('代码')
                ->setAttrib('class','border');
        
        $submitBtn = new Zend_Form_Element_Submit('submit');
        $submitBtn->setLabel('提交代码')
                ->setAttrib('class','submit');
        
        //判断传递的为 Qid 还是 Aid
        if (isset($qid))
        {
            $submitQid->setValue($qid);
        }
        else if(isset($aid))
        {
            //判断 aid 是否为数字先
            if(is_numeric($aid))
                $answer = $this->Validator->isAidValid($aid); //aid 是否有效
            else
                $answer = false;
            
            if($answer == false)
            {
                $this->view->ErrorInfo = Validator::AidError;
                $this->view->AidError = true;
                return; //aid 无效则结束
            }
            
            $submitQid->setValue($answer->getQuestion()->getId());
            $submitLang->setValue($answer->getLanguage()->getId());
            $submitTextarea->setValue($answer->getCode());
        }
        
        $submitForm->addElements(array($submitQid,$submitLang,$submitTextarea,$submitBtn));
        
        $this->view->submitForm = $submitForm;
        
        if($request->isPost())
        {
            $post = $request->getPost();
            if($submitForm->isValid($post))
            {
                $question = $this->Validator->isQidValid($post['qid']);
                if($question == false || $question->getMemo() == 'wait')
                {
                    $this->view->ErrorInfo = Validator::QidError;
                    return; //qid 无效则结束
                }
                
                $questionDb = new Application_Model_DbTable_Question();
                $question = $questionDb->getQuestionById($post['qid']);
                
                $lang =  new Application_Model_DbTable_Language();
                $curLang = $lang->getLanguageById($post['language']);
                
//                $submitTextarea->setValue($post['qid'].' '.$user->getName().' '
//                        .$langType[$post['language']].' '.$post['code']
//                        .$question->getRequireTime().' '.$question->getRequireMemory()
//                        .' '.$question->getInput().' '.$question->getOutput().' '
//                        .$curLang->getCompilerPath().' '.$curLang->getCompileArgs()
//                        );
                        
                //生成源码文件
//                $sourcePath = $_SERVER['DOCUMENT_ROOT'].'/whutoj/users/'.$user->getId().'_'.$post['qid'].$this->langType[$post['language']];
                $codeDir = dirname(dirname(dirname(__FILE__)));
                $sourcePath = $codeDir.'/users/'.$user->getId().'_'.$post['qid'].$this->langType[$post['language']];
                $fp = @fopen($sourcePath,'w');
                if ($fp)
                {
                    fwrite($fp, $post['code']);
                    fclose($fp);
                }
                else
                {
                    $this->view->ErrorInfo = '生成编译文件错误,请稍后再试或联系管理员';
                    exit;
                }
                
                $host = "127.0.0.1";
                $port = 5112;
                $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
                if($socket<0)
                echo "创建socket失败";
                else
                    echo "成功创建socket";
                echo "<br/>";
                $ret = socket_connect($socket, $host, $port);
                if($ret < 0)
                    echo "无法连接到主机:$host:$port";
                else
                    echo "成功连接到主机";
                echo "<br/>";
                $writedata = array();
                $writedata = '@OJ';
                $writedata .= $user->getId()."\r\n"; //uid
                $writedata .= $post['qid']."\r\n"; //qid
                $writedata .= $post['language']."\r\n"; //lid
                $writedata .= $curLang->getCompilerPath()." ".$curLang->getCompileArgs()."\r\n"; //编译器带参数路径
                //$writedata .= $sourcePath."\r\n";//用户提交代码的位置
                $writedata .= $question->getRequireTime()."\r\n";    //限制时间1000ms
                $writedata .= $question->getRequireMemory()."\r\n";    //限制内存1000KB
                $writedata .= $question->getInput()."\r\n";       //测试数据
                $writedata .= $question->getOutput()."\r\n";         //正确结果
                $writedata .= $this->checkSum($writedata)."/* Zend_CodeGenerator_Php_File-ClassMarker: {AnswerController} */"; //校验和,结束标识符
                
                if(socket_write($socket, $writedata, strlen($writedata))){
                    echo "成功向socket中写入数据:$writedata";
                }
                else
                    echo "写入数据失败,原因:".socket_strerror($socket);
                echo "<br />";
                socket_close($socket);
             }
        }
        
    }

    
    //本地端回传结果
    public function feedbackAction()
    {
        $testForm = new Zend_Form();
        $testForm->setMethod('POST');
        
        $testUid = new Zend_Form_Element_Text('uid');
        $testUid->setLabel('用户ID');
        
        $testQid = new Zend_Form_Element_Text('qid');
        $testQid->setLabel('问题ID');
        
        $testLang = new Zend_Form_Element_Text('lid');
        $testLang->setLabel('语言');
        
        $testCode = new Zend_Form_Element_Text('path');
        $testCode->setLabel('代码路径');
        
        $testCode = new Zend_Form_Element_Text('runoutput');
        $testCode->setLabel('实际输出');
        
        $testTime = new Zend_Form_Element_Text('runtime');
        $testTime->setLabel('运行时间');
        
        $testMem = new Zend_Form_Element_Text('runmem');
        $testMem->setlabel('运行内存');
        
        $testEcode = new Zend_Form_Element_Text('flag');
        $testEcode->setLabel('反馈代码');
        
        $testSubmit = new Zend_Form_Element_Submit('submit');
        $testSubmit->setLabel('提交');
        
        $testForm->addElements(array($testUid,$testQid,$testTime,$testMem,$testLang,$testCode,$testEcode,$testSubmit));
        
        $this->view->testForm = $testForm;
        
        $request = $this->getRequest();
        
        if (!$request->isPost())
            return;
        
        if(!isset($_POST['uid']))
            return;

        $answer = new Application_Model_Answer();

        $userDb = new Application_Model_DbTable_User();
        $questionDb = new Application_Model_DbTable_Question();
        $languageDb = new Application_Model_DbTable_Language();

        $answer->setUser($userDb->getUserById($_POST['uid']));
        $answer->setQuestion($questionDb->getQuestionById($_POST['qid']));
        $answer->setLanguage($languageDb->getLanguageById($_POST['lid']));

        //取用户代码,改为从生成代码的地方直接取,按 用户ID_题目ID.代码扩展名 格式
//                $codePath = $_SERVER['DOCUMENT_ROOT'].'/whutoj/users/'.$_POST['uid'].'_'.$_POST['qid'].$this->langType[$_POST['lid']];
        $codeDir = dirname(dirname(dirname(__FILE__)));
        $codePath = $codeDir.'/users/'.$_POST['uid'].'_'.$_POST['qid'].$this->langType[$_POST['lid']];

        $code = file_get_contents($codePath);
        $answer->setCode($code);

        $answer->setRunTime($_POST['runtime']);
        $answer->setRunMemory($_POST['runmem']);
        $answer->setOutput($_POST['runoutput']);
        $answer->setMemo($_POST['flag']);
        $answer->setTime(date( 'Y-m-d H:i:s', time()));
        //Todo: info,communicate with HuangJacky

        $answerDb = new Application_Model_DbTable_Answer();
        //查询是否已有此题相同语言的成功提交
        $answerIf = $answerDb->getOnesAnswersByQuestion(
                $userDb->getUserById($_POST['uid']),
                $questionDb->getQuestionById($_POST['qid']),
                $languageDb->getLanguageById($_POST['lid']));

        //若有且此次提交也为成功则更新
        if($answerIf && $_POST['flag'] == '$10000001')
        {
            $answer->setId($answerIf->getId());
            $answerDb->updateAnswer($answer);
        }//没有或此次提交失败则添加
        else
        {
            $answerDb->addAnswer($answer);
            //正确的提交则得分
            if($_POST['flag'] == '$10000001')
            {
                $score = new Application_Model_Score();
                $score->init($userDb->getUserById($_POST['uid']), $questionDb->getQuestionById($_POST['qid']), date( 'Y-m-d H:i:s', time()), 1);
                $scoreDb = new Application_Model_DbTable_Score();
                $scoreDb->addScore($score);
            }
        }
        
    }

    //查看某用户答题情况
    public function viewAction()
    {
        if (!$this->access->islogin())
        {
            $this->_redirect('/User/login');
            return;
        }
        
        $uid = $this->getRequest()->getParam('uid');
        $answerDb = new Application_Model_DbTable_Answer();
        $this->view->ecodes = $this->ecodes;
        $this->view->edit = false;
        
        if(isset($uid))
        {
            //判断 uid 是否为数字先
            if(is_numeric($uid))
                $user = $this->Validator->isUidValid($uid);//判断 uid 有效性
            else
                $user = false;
            
            if($user == false)
            {
                $this->view->ErrorInfo = Validator::UidError;
                return;
            }
            
            $userDb = new Application_Model_DbTable_User();
            $this->view->answers = $answerDb->getAnswersByUser($userDb->getUserById($uid));
            $this->view->user = $userDb->getUserById($uid);
            if($this->access->getSession()->getId() == $uid)
                $this->view->edit =true;
            $this->view->ecodesId = $this->ecodesId;
            return;
        }
        
        $userAnswers = $answerDb->getAnswersByUser($this->access->getSession());
        $this->view->answers = $userAnswers;
        $this->view->user = $this->access->getSession();
        $this->view->edit =true;
        $this->view->ecodesId = $this->ecodesId;
    }

    //答题情况列表
    public function listAction()
    {
        $pid = $this->getRequest()->getUserParam('pid');
        $this->view->showpage = true;
        
        $answerDb = new Application_Model_DbTable_Answer();
        $ans_count = $answerDb->countAnswers();//question 总条数
        
        //是否分页
        if($ans_count <= Validator::AnsListPagesize)
            $this->view->showpage = false;
        else
        {
            if($ans_count % Validator::AnsListPagesize)
            {
                $pages = (INT)($ans_count/Validator::AnsListPagesize+1);//有余数的情况
            }
            else
                $pages = $ans_count/Validator::AnsListPagesize;
            
            $this->view->pages = $pages;
        }
        
        //pid 的判断
        if(!isset($pid))
        {
            $answers = $answerDb->getAnswersByRange(0,Validator::AnsListPagesize);
            $pid = 1;
        }
        elseif($pid > 1 && $pid <= $pages)
            $answers = $answerDb->getAnswersByRange(Validator::AnsListPagesize*($pid-1),Validator::AnsListPagesize);
        else
            $this->_redirect('Answer/list');//pid 不合法直接跳转首页
        
        $this->view->answers = $answers;
        $this->view->pid = $pid;
        $this->view->ecodes = $this->ecodes;
        $this->view->ecodesId = $this->ecodesId;
    }
    
    //校验和
    public function checkSum($array)
    {
       $array = str_replace("\r\n", "", $array);

       $ascSum = 0;

       for($i = 0; $i<strlen($array); $i++)
       {
           $ascSum += ord(substr($array, $i, 1));
       }
//       $ascSum = (string)decbin($ascSum);
       //扩展为两字节
//       $ascSum = str_pad($ascSum, 16, "0", STR_PAD_LEFT);
       //转换为 Hex
//       $checkSum = dechex(bindec(substr($ascSum, -16, 8)));
//       $checkSum .= dechex(bindec(substr($ascSum, -8)));
       
       $checkSum = dechex($ascSum);
       
       return $checkSum;
    }

}
